;**************************************************
; memory.inc
; Memory detection routines for bootloader stage
; Reindeer OS
;**************************************************

bits 16

; Memory map structure
struc memory_map_entry
	.baseAddress		resq	1		; 64 bit
	.length				resq	1		; 64 bit
	.type				resd	1		; 32 bit
	.acpi_null			resd	1		; 32 bit
endstruc

; Get memory map (from bios)
; --------------------------
; INPUT:
; es:di - destination buffer for entries
; RETURN:
; bp = entry count
BiosGetMemoryMap:
	pushad
	xor		ebx, ebx		; clear ebx
	xor		bp, bp			; clear bp
	mov		edx, 'PAMS'		; SNAP
	mov		eax, 0xE820		; function get memory map
	mov		ecx, 24			; memory map entry struct has 24 bytes
	int		0x15			; call bios function
	jc		.error
	cmp		eax, 'PAMS'		; bios should return SNAP in eax
	jne		.error
	test	ebx, ebx		; if ebx=0 then list is one enry long, so we are done here...
	je		.error
	jmp		.start
.next_entry:
	mov		edx, 'PAMS'		; some bios can trash this register
	mov		ecx, 24			
	mov		eax, 0xE820
	int		0x15
.start:
	jcxz	.skip_entry		; if actual returned bytes is 0, skip entry
.notext:
	mov		ecx, [es:di+memory_map_entry.length]	; get length of entry (low dword)
	test	ecx, ecx								; if length is 0 skip it
	jne		short .good_entry
	mov		ecx, [es:di+memory_map_entry.length+4]	; get length of entry (upper dword)
	jecxz	.skip_entry
.good_entry:
	inc		bp				; increment entry count
	add		di, 24			; point di to next entry in buffer
.skip_entry:
	cmp		ebx, 0			; if ebx is 0 list is done
	jne		.next_entry		; go to next entry
	jmp		.done
.error:
	stc
.done:
	popad
	ret

; Get memory size for >64M configurations (32 bit)
; ------------------------------------------------
; RETURN:
; ax = kB between 1MB and 16MB
; bx = number of 64K blocks above 16MB
; bx = 0 and ax = -1 on error
BiosGetMemorySize64MB_32bit:
	push	ecx
	push	edx
	xor		ecx, ecx
	xor		edx, edx
	mov		ax, 0xE881			; bios function get memory size
	int		0x15				; call bios
	jc		.error
	cmp		ah, 0x86			; unsupported funtion
	je		.error
	cmp		ah, 0x80			; invalid command
	je		.error
	jcxz	.use_ax				; bios may have stored it in ax, bx or cx, dx. Test if cx is 0 ...
	mov		ax, cx				; if not, so it should contain mem size, store it as return result
	mov		bx, dx
.use_ax:
	pop		edx					
	pop		ecx
	ret
.error:
	mov		ax, -1
	mov		bx, 0
	pop		edx
	pop		ecx
	ret

; Get memory size for >64M configuration
; --------------------------------------
; RETURN:
; ax = kB between 1MB and 16MB
; bx = number of 64K blocks above 16MB
; bx = 0 and ax = -1 on error
BiosGetMemorySize64MB:
	push	ecx
	push	edx
	xor		ecx, ecx
	xor		edx, edx
	mov		ax, 0xe801			; bios function identificator
	int		0x15				; call bios
	jc		.error
	cmp		ah, 0x86			; unsupported function :(
	je		.error
	cmp		ah, 0x80			; invalid command	:(
	je		.error
	jcxz	.use_ax		
	mov		ax, cx
	mov		bx, dx		
.use_ax:
	pop		edx
	pop		ecx
	ret
.error:
	mov		ax, -1
	mov		bx, 0
	pop		edx
	pop		ecx
	ret

; Get amount of cintiguous kB from addr 0
; ---------------------------------------
; RETURN:
;	ax = kB size from address 0
BiosGetMemorySize:
	int 0x12
	ret

; Get contiguous extended memory size
; RETURN:
;	ax = kB size above 1MB, ax = -1 on error

BiosGetExtendedMemorySize:
	mov		ax, 0x88
	int		0x15
	jc		.error
	test	ax, ax		; if size = 0
	je		.error
	cmp		ah, 0x86	; unsupported function
	je		.error
	cmp		ah, 0x80	; invalid command
	je		.error
	ret
.error:
	mov		ax, -1
	ret